package c_user

import (
	"encoding/json"
	"fmt"
	"jihe.common/protos/user_server/proto"
	"jihe.common/tool"
	"strings"
)

func (s *Model) Create(in *proto.UserCUser) (ret *proto.UserCUser, err error) {
	ret = new(proto.UserCUser)
	in.Id = fmt.Sprintf("%d", tool.GetSnowflakeId())
	intoMap := make(map[string]interface{})
	intoMap["id"] = in.Id
	intoMap["age"] = in.Age
	intoMap["phone"] = in.Phone
	intoMap["sex"] = in.Sex
	intoMap["name"] = in.Name
	if in.BodyData != nil {
		bodyDataB, e := json.Marshal(in.BodyData)
		if e != nil {
			err = e
			return
		}
		intoMap["body_data"] = string(bodyDataB)
	}
	fields, vals, args := make([]string, 0), make([]interface{}, 0), make([]string, 0)
	valNum := 0
	for field, val := range intoMap {
		fields = append(fields, field)
		vals = append(vals, val)
		valNum++
		args = append(args, fmt.Sprintf("$%d", valNum))
	}
	sqlStr := fmt.Sprintf("INSERT INTO %s ("+strings.Join(fields, ",")+")VALUES("+strings.Join(args, ",")+")", s.Name)
	_, err = s.Db.Exec(sqlStr, vals...)
	if err != nil {
		return
	}
	ret = in
	return
}

func (s *Tx) Create(in *proto.UserCUser) (ret *proto.UserCUser, err error) {
	ret = new(proto.UserCUser)
	in.Id = fmt.Sprintf("%d", tool.GetSnowflakeId())
	intoMap := make(map[string]interface{})
	intoMap["id"] = in.Id
	intoMap["age"] = in.Age
	intoMap["phone"] = in.Phone
	intoMap["sex"] = in.Sex
	intoMap["name"] = in.Name
	if in.BodyData != nil {
		bodyDataB, e := json.Marshal(in.BodyData)
		if e != nil {
			err = e
			return
		}
		intoMap["body_data"] = string(bodyDataB)
	}
	fields, vals, args := make([]string, 0), make([]interface{}, 0), make([]string, 0)
	valNum := 0
	for field, val := range intoMap {
		fields = append(fields, field)
		vals = append(vals, val)
		valNum++
		args = append(args, fmt.Sprintf("$%d", valNum))
	}
	sqlStr := fmt.Sprintf("INSERT INTO %s ("+strings.Join(fields, ",")+")VALUES("+strings.Join(args, ",")+")", s.Name)
	_, err = s.Db.Exec(sqlStr, vals...)
	if err != nil {
		return
	}
	ret = in
	return
}

func (s *Model) UpdateByPhone(in *proto.UserCUser) (err error) {
	intoMap := make(map[string]interface{})
	if in.Age != 0 {
		intoMap["age"] = in.Age
	}
	if in.Sex != 0 {
		intoMap["sex"] = in.Sex
	}
	intoMap["phone"] = in.Phone
	if in.Name != "" {
		intoMap["name"] = in.Name
	}
	if in.BodyData != nil {
		bodyDataB, e := json.Marshal(in.BodyData)
		if e != nil {
			err = e
			return
		}
		intoMap["body_data"] = string(bodyDataB)
	}
	if in.Photos != nil {
		photosBytes, e := json.Marshal(in.Photos)
		if e != nil {
			err = e
			return
		}
		intoMap["photos"] = string(photosBytes)
	}
	fields, vals := make([]string, 0), make([]interface{}, 0)
	valNum := 0
	for field, val := range intoMap {
		valNum++
		fields = append(fields, fmt.Sprintf("%s=$%d", field, valNum))
		vals = append(vals, val)
	}
	sqlStr := fmt.Sprintf("update %s set "+strings.Join(fields, ",")+" where phone = '%s'", s.Name, in.Phone)
	_, err = s.Db.Exec(sqlStr, vals...)
	if err != nil {
		return
	}
	return
}

func (s *Model) GetByIds(in *proto.UserGetCUsersByIdsReq) (ret []*proto.UserCUser, err error) {
	args := make([]string, len(in.Uids))
	vals := make([]interface{}, len(in.Uids))
	for k, v := range in.Uids {
		args[k] = fmt.Sprintf("$%d", k+1)
		vals[k] = v
	}
	sqlStr := fmt.Sprintf("select id, name, age, phone, sex, body_data from %s where id in ("+strings.Join(args, ",")+") order by created_at desc", s.Name)
	rows, err := s.Db.Query(sqlStr, vals...)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		item := &proto.UserCUser{}
		var (
			bodyDataB []byte
		)
		err = rows.Scan(&item.Id, &item.Name, &item.Age, &item.Phone, &item.Sex, &bodyDataB)
		if err != nil {
			return
		}
		json.Unmarshal(bodyDataB, &item.BodyData)
		ret = append(ret, item)
	}
	return
}

func (s *Model) GetByPhone(phone string) (ret *proto.UserCUser, err error) {
	ret = new(proto.UserCUser)
	sqlStr := fmt.Sprintf("select id, name, age, phone, sex from %s where phone = $1", s.Name)
	err = s.Db.QueryRow(sqlStr, phone).Scan(&ret.Id, &ret.Name, &ret.Age, &ret.Phone, &ret.Sex)
	if err != nil {
		return
	}
	return
}

func (s *Model) GetList(in *proto.UserListReq) (ret *proto.UserCListRes, err error) {
	in.Page--
	ret = new(proto.UserCListRes)
	ret.Page = in.Page + 1
	ret.PageSize = in.PageSize
	sqls := make([]string, 0)
	vals := make([]interface{}, 0)
	countSqlStr := fmt.Sprintf("select count(*) from %s where 1=1 ", s.Name)
	sqlStr := fmt.Sprintf("select id,name,phone,body_data,photos,sex from %s where 1=1 ", s.Name)
	if in.Phone != "" {
		vals = append(vals, in.Phone)
		sqls = append(sqls, "AND phone = ")
	}
	if in.Name != "" {
		vals = append(vals, in.Name)
		sqls = append(sqls, "AND name = ")
	}

	for k, v := range sqls {
		countSqlStr += fmt.Sprintf("%s$%d ", v, k+1)
	}

	row := s.Db.QueryRow(countSqlStr, vals...)
	err = row.Scan(&ret.Total)
	if err != nil {
		return
	}

	vals = append(vals, in.Page*in.PageSize)
	sqls = append(sqls, "ORDER BY created_at DESC OFFSET ")
	vals = append(vals, in.PageSize)
	sqls = append(sqls, "LIMIT ")
	for k, v := range sqls {
		countSqlStr += fmt.Sprintf("%s$%d ", v, k+1)
		sqlStr += fmt.Sprintf("%s$%d ", v, k+1)
	}

	rows, err := s.Db.Query(sqlStr, vals...)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		item := &proto.UserCUser{}
		var (
			bodyDataB []byte
			photos    []byte
		)
		err = rows.Scan(&item.Id, &item.Name, &item.Phone, &bodyDataB, &photos, &item.Sex)
		if err != nil {
			return
		}
		json.Unmarshal(bodyDataB, &item.BodyData)
		json.Unmarshal(photos, &item.Photos)
		ret.List = append(ret.List, item)
	}
	return
}
